<?php

defined('BASEPATH') or exit('No direct script access allowed');

/**
 * Base Model
 *
 */
class Base_Model extends CI_Model
{

	/**
	 * It is used to store error information.
	 *
	 * @var string
	 * @access public
	 */
	public $error = '';

	/**
	 * Table name
	 *
	 * @var string
	 * @access protected
	 */
	public static $table_name = '';

	/**
	 *Table primary key, if no default is used "Id".
	 *
	 * @var string
	 * @access protected
	 */
	protected $key = 'id';

	/**
	 * Database connection configuration
	 *
	 * @var mixed
	 * @access protected
	 */
	protected $db_group = '';

	/**
	 * 是否返回最后新增的ID
	 *
	 * @var bool
	 */
	protected $return_insert_id = FALSE;

	/**
	 * 查询返回的数组结果键值字段
	 *
	 * @var array
	 */
	protected $result_array_key_field = null;

	//--------------------------------------------------------------------

	/**
	 * MY_Model constructor
	 *
	 * @return void
	 */
	public function __construct()
	{
		parent::__construct();

		$this->ini_dbcon();
	}

	//---------------------------------------------------------------

	public function ini_dbcon()
	{
		// 另外设置的数据库连接
		if ( ! empty($this->db_group))
		{
			$this->db = $this->load->database($this->db_group, TRUE);
		}

		if ( ! isset($this->db))
		{
			$this->load->database();
		}
	}

	//---------------------------------------------------------------

	/**
	 * 获得表名或别名
	 * @param bool $table_name_with_alias 为true时，若设置了别名，则返回 表名+空格+别名，反之返回 表名；为false时，若设置了别名，则返回 别名，反之返回 表名；默认true
	 * @return string
	 */
	private function table_name($table_name_with_alias=true)
	{
		$aliased_tables = $this->db->qb_aliased_tables;
		$has_alias = (isset($aliased_tables[static::$table_name]) && $aliased_tables[static::$table_name] != '') ? true : false;
		$table_alias = $has_alias ? $aliased_tables[static::$table_name] : '';
		return $table_name_with_alias ? static::$table_name.($table_alias != '' ? ' '.$table_alias : '') : ($has_alias ? $table_alias : static::$table_name);
	}//end table_name()
	//---------------------------------------------------------------

	/**
	 * 重新遍历$result_array，特定字段值为数组键值
	 * @param array $result_array result_array二维数组数据
	 * @return array
	 */
	private function reinit_result_array($result_array)
	{
		if(is_array($result_array) && $this->result_array_key_field != null && array_key_exists(0, $result_array) && array_key_exists($this->result_array_key_field, $result_array[0])){
			$tmp = $result_array;
			unset($result_array);
			foreach ($tmp as $value) {
				$result_array[$value[$this->result_array_key_field]] = $value;
			}
			$this->result_array_key_field = null;
		}
		$this->result_array_key_field = null;

		return $result_array;
	}//end reinit_result_array()

	// ---------------------------------------------------------------

	/**
	 * 定义result_array()结果数组键值字段
	 * @param string $field
	 * @return object
	 */
	public function result_key_field($field = '')
	{
		if($field != '') {
			$this->result_array_key_field = $field;
		}
		return $this;
	}

	//---------------------------------------------------------------

	/**
	 * 根据主键查询一条数据.
	 * id为空时，此前必须设置有where、like或者limit，才能执行查询，否则返回false.
	 *
	 * id不为空时，必须保证主键key已经设置
	 *
	 * @param string $id 主键记录.
	 *
	 * @return array OR FALSE.
	 */
	public function find($id='')
	{
		if($id == '' && empty($this->db->qb_where) && ! $this->db->qb_limit){
			$this->error = '未设置查询条件';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] ' . $this->error);
			$this->db->reset_select();
			return FALSE;
		}
		
		if($id == ''){
			$query = $this->db->get($this->table_name());
		}else{
			$query = $this->db->get_where($this->table_name(), array($this->table_name(false) . '.' . $this->key => $id));
		}

		if ( ! $query->num_rows())
		{
			return FALSE;
		}

		return $query->row_array();

	}//end find()

	//---------------------------------------------------------------

	/**
	 * 从数据表查询多条数据.
	 *
	 * @return array OR FALSE.
	 */
	public function find_all()
	{
		$query = $this->db->get($this->table_name());

		if (!$query->num_rows())
		{
			return FALSE;
		}

		$ret = $query->result_array();

		return $this->reinit_result_array($ret);

	}//end find_all()

	//---------------------------------------------------------------

	/**
	 * 根据给定的条件查询多条数据.
	 *
	 * @param mixed  $field	查询的字段也是包含字段和查询值的数组.
	 * @param mixed  $value (可选)查询的条件值.
	 * @param string $type  条件类型 'and' or 'or'.
	 *
	 * @return array OR FALSE.
	 */
	public function find_all_by($field, $value = NULL, $type = 'and')
	{
		// 设置为数组
		if ( ! is_array($field))
		{
			$field = array($field => $value);
		}

		if (strtolower($type) == 'or')
		{
			$this->db->or_where($field);
		}
		else
		{
			$this->db->where($field);
		}

		return $this->find_all();

	}//end find_all_by()

	//--------------------------------------------------------------------

	/**
	 * 根据条件获取符合条件的第一条数据.
	 *
	 * @param mixed  $field	查询的字段也是包含字段和查询值的数组.
	 * @param mixed  $value (可选)查询的条件值.
	 * @param string $type  条件类型 'and' or 'or'.
	 *
	 * @return array OR FALSE.
	 */
	public function find_by($field, $value = '', $type = 'and')
	{
		if (empty($field) || ( ! is_array($field) && empty($value)))
		{
			$this->error = '没有足够的条件查询数据';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] ' . $this->error);
			$this->db->reset_select();
			return FALSE;
		}

		if ( ! is_array($field))
		{
			$field = array($field => $value);
		}

		if (strtolower($type) == 'or')
		{
			$this->db->or_where($field);
		}
		else
		{
			$this->db->where($field);
		}

		$query = $this->db->get($this->table_name());

		if ( ! $query->num_rows())
		{
			return FALSE;
		}
		// 返回第一条数据
		return $query->row_array();

	}//end find_by()

	//---------------------------------------------------------------

	/**
	 * 返回sql执行的结果(1条).
	 * @param string  $sql	查询的字段也是包含字段和查询值的数组.
	 * @param array  $params (可选)绑定参数数组
	 *
	 * @return array.
	 */
	public function row_query($sql, $params = array() ,$reconnect = FALSE )
	{
		if (is_string($sql) && trim($sql) != '')
		{
			$reconnect === TRUE AND $this->db->reconnect();
			$query = $this->query($sql, $params);
			$row = $query->row_array();
			$this->db->free_all_result();
			return $row;
		}
		return array();

	}//end row_query()

	//---------------------------------------------------------------

	/**
	 * 执行sql语句
	 * @param string $sql	sql语句（原生参数）
	 * @param mixed $binds 绑定参数数组（原生参数），默认FALSE
	 * @param bool $return_object 返回对象（原生参数），默认TRUE
	 * @param string $return_data 返回执行数据（新增参数）,默认空，可选值one|all,one相当于$this->db->query()->row_array(),all相当于$this->db->query()->result_array()
	 *
	 * @return mixed.
	 */
	public function query($sql, $binds = FALSE, $return_object = TRUE, $return_data='')
	{
		$query = $this->db->query($sql, $binds, $return_object);
		if($return_data == 'one'){
			return $query->row_array();
		}
		if($return_data == 'all'){
			return $this->reinit_result_array($query->result_array());
		}
		return $query;
	}//end query()

	//---------------------------------------------------------------

	/**
	 * 返回表所有字段
	 * @param string $table 表名
	 *
	 * @return array.
	 */
	public function list_fields($table='')
	{
		return $this->db->list_fields($table == '' ? $this->table_name() : $table);
	}//end list_fields()

	//---------------------------------------------------------------

	/**
	 * 向数据库新增一条数据.
	 *
	 * @param array $data 用于新增到数据库的数据.
	 *
	 * @return bool|mixed 新增的id or FALSE.
	 */
	public function insert($data)
	{
		// 前置操作
		$data = $this->trigger('before_insert', $data);

		// Insert it
		$status = $this->db->insert($this->table_name(), $data);

		if ($status == FALSE)
		{
			$this->error = $this->get_db_error_message();
		}
		elseif ($this->return_insert_id)
		{
			$id = $this->db->insert_id();

			$status = $this->trigger('after_insert', $id);
		}

		return $status;

	}//end insert()

	//---------------------------------------------------------------

	/**
	 * 向数据库新增一条数据.
	 *
	 * @param array $data 用于新增到数据库的数据.
	 *
	 * @return bool|mixed 新增的id or FALSE.
	 */
	public function replace($data)
	{
		// 前置操作
		$data = $this->trigger('before_insert', $data);

		// Insert it
		$status = $this->db->replace($this->table_name(), $data);

		if ($status == FALSE)
		{
			$this->error = $this->get_db_error_message();
		}
		elseif ($this->return_insert_id)
		{
			$id = $this->db->insert_id();

			$status = $this->trigger('after_insert', $id);
		}

		return $status;

	}//end insert()

	//---------------------------------------------------------------

	/**
	 * 批量新增数据.
	 *
	 * @param array $data 用于新增的数组.
	 *
	 * @return bool
	 */
	public function insert_batch($data)
	{
		foreach ($data as $key => &$record)
		{
			$record = $this->trigger('before_insert', $record);
		}

		// Insert it
		$status = $this->db->insert_batch($this->table_name(), $data);

		if ($status === FALSE)
		{
			$this->error = $this->get_db_error_message();
			return FALSE;
		}

		return TRUE;

	}//end insert_batch()

	//---------------------------------------------------------------

	/**
	 * 更新数据.
	 *
	 * @example sql: UPDATE Ta SET a=1,b=b+1 WHERE c=1; 
	 * @example $this->model->set('a', 1)->set('b', 'b+1', false)->where('c', 1)->update();
	 * @example $this->model->set('a', 1)->set('b', 'b+1', false)->update(array(), array('c'=>1));
	 * @example $this->model->where(array('c'=>1))->update(array('a'=>1, 'b'=>'b+1'));
	 * @example $this->model->update(array('a'=>1, 'b'=>'b+1'), array('c'=>1));
	 *
	 * @param mixed $data	更新的数据，可省，默认空array，但前提是已有set设置更新数据.
	 * @param mixed	$where	更新条件，可省，默认空array，但前提是已有设置where.
	 *
	 * @return bool TRUE/FALSE
	 */
	public function update($data=array(), $where=array())
	{
		$data = $this->trigger('before_update', $data);
		
		// 处理自增自减
		$tmp_data = $data;
		foreach ($tmp_data as $key=>$val)
		{
			$_key = trim($key);
			$_val = trim($val);
			if(preg_match("/^[ ]?[`]?".$_key."[`]?[ ]?(\+|\-)[ ]?\d+(\.\d+)?[ ]?$/", $_val)){
				$this->db->set($_key, $_val, FALSE);
				unset($data[$key]);
			}
		}

		if ( ! is_array($where))
		{
			$where = array($this->key => $where);
		}

		! empty($where) && $this->db->where($where);
		
		$flag = ( (is_array($data) && ! empty($data)) || ! empty($this->db->qb_set ) ) && ( (is_array($where) && ! empty($where) ) || ! empty($this->db->qb_where) );
		if( ! $flag){
			$this->error = '未设置更新条件或者更新数据或者为空';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] ' . $this->error);
			$this->db->reset_select();
			return FALSE;
		}
		

		$result = $this->db->update($this->table_name(), $data, $where);

		if ($result)
		{
			$this->trigger('after_update', array($data, $result));
			return TRUE;
		}

		return FALSE;

	}//end update()

	//---------------------------------------------------------------

	/**
	 * 根据指定的字段为条件更新数据.
	 *
	 * @param string $field 指定的字段.
	 * @param string $value 比配的值.
	 * @param array  $data  更新的数据.
	 *
	 * @return bool TRUE/FALSE
	 */
	public function update_where($field, $value, $data)
	{
		return $this->update(array($field => $value), $data);
	}//end update_where()

	//---------------------------------------------------------------

	/**
	 * 批量更新数据.
	 *
	 * @param array  $data  更新的数据.
	 * @param string $index 键名
	 *
	 * @return bool TRUE/FALSE
	 */
	public function update_batch($data, $index)
	{
		$result = $this->db->update_batch($this->table_name(), $data, $index);

		return empty($result) ? TRUE : FALSE;

	}//end update_batch()

	//--------------------------------------------------------------------

	/**
	 * 删除数据.
	 *
	 * @example $this->model->delete(1);*
	 * @example $this->model->delete(array(id=>1));
	 * @example $this->model->where('key', 'value')->delete();
	 *
	 * @param mixed $id (可选) 主键值.
	 *
	 * @return bool TRUE/FALSE
	 */
	public function delete($id = NULL)
	{
		$this->trigger('before_delete', $id);

		if ( ! empty($id) && is_string($id))
		{
			$this->db->where($this->key, $id);
		}
		elseif (is_array($id))
		{
			$this->db->where($id);
		}
		
		if(empty($this->db->qb_where)){
			$this->error = '未设置删除条件';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] ' . $this->error);
			$this->db->reset_select();
			return FALSE;
		}

		$this->db->delete($this->table_name());

		if ($this->db->affected_rows())
		{
			$this->trigger('after_delete', $id);
			return TRUE;
		}

		$this->error = 'DB Error: ' . $this->get_db_error_message();

		return FALSE;

	}//end delete()

	//---------------------------------------------------------------

	/**
	 * 根据指定指定条件删除数据.
	 *
	 * @param mixed/array $data 字符串的条件或者数组
	 *
	 * @example 1) $this->model->delete_where(array( 'key' => 'value', 'key2' => 'value2' ))
	 * @example 2) $this->model->delete_where("`key` = 'value' AND `key2` = 'value2'")
	 *
	 * @return bool TRUE/FALSE
	 */
	public function delete_where($where)
	{
		$where = $this->trigger('before_delete', $where);

		$this->db->where($where);

		$this->db->delete($this->table_name());

		$result = $this->db->affected_rows();

		if ($result)
		{
			$this->trigger('after_delete', $result);

			return $result;
		}

		$this->error = 'DB Error: ' . $this->get_db_error_message();

		return FALSE;

	}//end delete_where()

	//---------------------------------------------------------------

	//---------------------------------------------------------------
	// HELPER FUNCTIONS
	//---------------------------------------------------------------

	/**
	 * 查询指定条件的数据是否唯一存在.
	 *
	 * @param string $value 匹配$field的值.
	 * @param string $field	用于查询的字段.
	 *
	 * @return bool TRUE/FALSE
	 */
	public function is_unique($value='', $field='')
	{
		if(is_string($value) && $value != '' && $field == '' && $this->key != ''){
			$this->db->where($this->key, $value);
		}
		if(empty($this->db->qb_where))
		{
			$this->error = '没有足够的条件来检测数据的唯一性';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] '. $this->error);
			$this->db->reset_select();
			return FALSE;
		}

		$count = $this->db->count_all_results($this->table_name());

		if ($count === 0)
		{
			return TRUE;
		}

		return FALSE;

	}//end is_unique()

	//---------------------------------------------------------------

	/**
	 * 返回表中的行数.
	 *
	 * @return int
	 */
	public function count_all()
	{
		$count = $this->db->count_all_results($this->table_name());
		
		return $count;
	}//end count_all()

	//---------------------------------------------------------------

	/**
	 * 根据条件返回表中的行数.
	 *
	 * @param string/array $field	要查询的字段,可以是数组.
	 * @param string $value			(可选)查询值.
	 *
	 * @example 1) count_by("`key` = 'value' AND `key2` = 'value2'")
	 * @example 2) count_by('key', 'value')
	 * @example 2) count_by($value)
	 * @example 3) count_by(array('key' => 'value', 'key2' => 'value2'))
	 *
	 * @return bool|int
	 */
	public function count_by($field, $value = NULL)
	{

		if(is_string($field) && ! empty($field) && strpos($field, '=') === false && empty($value) && $this->key != ''){
			$this->db->where($this->key, $field);
		}
		elseif(is_string($field) && ! empty($field) && strpos($field, '=') === false && ! empty($value))
		{
			$this->db->where($field, $value);
		}
		elseif(is_array($field))
		{
			$this->db->where($field);
		}
		
		if(empty($this->db->qb_where))
		{
			$this->error = '没有足够的条件来统计结果';
			$this->logit('['. get_class($this) .': '. __METHOD__ .'] '. $this->error);
			$this->db->reset_select();
			return FALSE;
		}

		return $this->count_all();

	}//end count_by()

	//---------------------------------------------------------------

	/**
	 * 根据主键获取一条数据的单个字段值.
	 *
	 * @param mixed  $id	查询的主键值.
	 * @param string $field 要获取的字段.
	 *
	 * @return bool|mixed 获取的字段值.
	 */
	public function get_field($id, $field)
	{
		$query = $this->db->select($field)
		->where($this->key, $id)
		->get($this->table_name());

		if ($query && $query->num_rows() > 0)
		{
			return $query->row()->{$field};
		}

		return FALSE;

	}//end get_field()

	//--------------------------------------------------------------------

	//--------------------------------------------------------------------
	// !CHAINABLE UTILITY METHODS
	//--------------------------------------------------------------------

	/**
	 * 排序
	 * 基于CI的重写方法可使用数组
	 *
	 * @param mixed  $field 要排序的字段或者数组.
	 * @param string $order (可选) 排序的方向 ('asc' or 'desc').
	 *
	 * @example 1) order_by("`key` DESC, `key2` ASC")
	 * @example 2) order_by('key', 'DESC')
	 * @example 3) order_by(array('key' => 'DESC', 'key2' => 'ASC'))
	 *
	 * @return object		returns $this 用于链式操作.
	 */
	public function order_by($field, $order = '')
	{
		if ( ! empty($field))
		{
			if (is_string($field))
			{
				$this->db->order_by($field, $order);
			}
			elseif (is_array($field))
			{
				foreach ($field as $f => $o)
				{
					$this->db->order_by($f, $o);
				}
			}
		}

		return $this;

	}//end order_by()

	/**
	 * FIELD排序
	 *
	 * @param mixed  $field 要排序的字段或者数组.
	 * @param mixed $array 排序的值，字符串或数组
	 *
	 * @example 1) order_by_field("`key`, 1,2,3")
	 * @example 2) order_by_field('key', '1,2,3')
	 * @example 2) order_by_field('key', array(1,2,3))
	 * @example 3) order_by_field(array('key' => '1,2,3', 'key2' => array(1,2,3)))
	 *
	 * @return object		returns $this 用于链式操作.
	 */
	public function order_by_field($field, $array = array(), $escape = NULL)
	{
		$sql = '';
		if ( ! empty($field))
		{
			if(is_string($field) && empty($array)){
				$findex = strpos($field, ',');
				if($findex !== false){
					$array = substr($field, $findex+1);
					$field = trim(substr($field, 0, $findex));
				}
			}
			elseif (is_string($field) && is_array($array))
			{
				$tmp = array();
				foreach ($array as $value) {
					$tmp[] = "'".addslashes($value)."'";
				}
				$array = implode(', ', $tmp);
			}
			elseif (is_array($field) && empty($array))
			{
				foreach ($field as $f => $o)
				{
					if(is_array($o)){
						$tmp = array();
						foreach ($o as $value) {
							$tmp[] = "'".addslashes($value)."'";
						}
						$this->order_by_field($f, implode(',', $tmp));
					}else{
						$this->order_by_field($f, $o);
					}
				}
			}
				
			if ( ! empty($field) && is_string($field) && ! empty($array) && is_string($array))
			{
				if ( ! in_array($field, $this->db->qb_aliased_tables))
				{
					$field = $this->db->protect_identifiers($field);
				}

				$field = ' FIELD ('.$field.', '.$array.')';
				is_bool($escape) OR $escape = TRUE;
				$orderby = array(array('field' => $field, 'direction' => '', 'escape' => $escape));
				$this->db->qb_orderby = array_merge($this->db->qb_orderby, $orderby);

				if ($this->db->qb_caching === TRUE)
				{
					$this->db->qb_cache_orderby = array_merge($this->db->qb_cache_orderby, $orderby);
					$this->db->qb_cache_exists = array_merge($this->db->qb_cache_exists, array('orderby'));
				}
			}
		}

		return $this;

	}//end order_by()

	//--------------------------------------------------------------------

	//--------------------------------------------------------------------
	// Scope Methods
	//--------------------------------------------------------------------

	/**
	 * 设置是否将返回新插入的ID
	 *
	 * @param bool $return (可选) 默认TRUE
	 *
	 * @return object		returns $this 用于链式操作
	 */
	public function return_insert_id($return = TRUE)
	{
		$this->return_insert_id = (bool)$return;

		return $this;
	  
	}//end return_insert_id()

	//---------------------------------------------------------------
	// !UTILITY FUNCTIONS
	//---------------------------------------------------------------

	/**
	 * 触发model的特定事件
	 * model中方法的access须定义protected,方法名带"_"前缀,
	 * 如：protected function _before_find($data){...}
	 *
	 * @access public
	 *
	 * @param string 	$event 	要执行的事件
	 * @param mixed 	$data 	需要进行处理的数据.
	 *
	 * @return mixed
	 */
	public function trigger($event, $data = FALSE)
	{
		$method = "_{$event}";

		return $this->{$method}($data);

	}//end trigger();

	//---------------------------------------------------------------

	/**
	 * 查询的前置操作(目前没有使用)
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * @return void
	 */
	protected function _before_find() {} // end _before_find()

	//---------------------------------------------------------------

	/**
	 * 查询的后置操作(目前没有使用)
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * @param array $data 查询得到的结果数据
	 * @return mixed
	 */
	protected function _after_find($data)
	{
		return $data;
	}//end _after_find()

	//---------------------------------------------------------------

	/**
	 * 插入的前置操作
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * @param array $data 要新增的数据
	 * @return mixed
	 */
	protected function _before_insert($data)
	{
		return $data;
	}//end _before_insert()

	//---------------------------------------------------------------

	/**
	 * 插入的后置操作
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * 注意：
	 * 如果新增的数据需要返回新增ID,操作调用这个方法
	 * 另：
	 * 批量添加不会调用这个方法
	 *
	 * @param int $id 新增主键ID
	 * @return bool|mixed 可以是新增的ID或者操作失败返回的FALSE
	 */
	protected function _after_insert($id)
	{
		return $id;
	}//end _after_insert()

	//---------------------------------------------------------------

	/**
	 * 更新的前置操作
	 * 在数据验证之后调用
	 *
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * 注意：
	 * 批量更新不会调用这个方法
	 *
	 * @param array $data 要更新的数据
	 * @return array 处理过的更新数据
	 */
	protected function _before_update($data)
	{
		return $data;
	}//end _before_update()

	//--------------------------------------------------------------------

	/**
	 * 更新的后置操作
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * 注意：
	 * 批量更新不会调用这个方法
	 *
	 * @param array $data 包含更新的数据和更新处理结果,如：array(更新的数据, 处理结果)
	 * @return void
	 */
	protected function _after_update($data) {} //end _after_update()

	//--------------------------------------------------------------------

	/**
	 * 删除的前置操作
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * @param array $id 要更新数据ID
	 * @return void
	 */
	protected function _before_delete($data)
	{
		return $data;
	}//end _before_delete()

	//---------------------------------------------------------------

	/**
	 * 删除的后置操作
	 * 你可以在model中覆盖这个方法,实现自己的操作
	 *
	 * @param bool|int $result 处理结果,一般是处理结果影响的行数
	 * @return void
	 */
	protected function _after_delete($result) {} //end _after_delete()

	//--------------------------------------------------------------------

	/**
	 * 设置数据库链接
	 *
	 * @param string $db_group
	 */
	public function set_db_con($db_group)
	{
		if (class_exists('CI_DB') AND isset($this->db))
		{
			$this->db->close();
		}
		$this->db = $this->load->database($db_group, TRUE);
	}

	//--------------------------------------------------------------------

	/**
	 * 获取来与于数据库的错误信息
	 *
	 * @return string
	 */
	protected function get_db_error_message()
	{
		switch ($this->db->platform())
		{
			case 'mysql':
				return mysql_error($this->db->conn_id);
			case 'mysqli':
				return mysqli_error($this->db->conn_id);
			default:
				return $this->db->_error_message();
		}

	}//end get_db_error_message()

	//--------------------------------------------------------------------

	/**
	 * 获取当前设置的表名
	 *
	 * @return string static::$table_name (当前model使用的表名)
	 */
	public function get_table()
	{
		return static::$table_name;

	}//end get_table()

	//--------------------------------------------------------------------

	/**
	 * 设置当前model对应表的别名，用于join表查询，必须在最前面
	 *
	 * 如：$this->xx_model->set_table_alias('u')->select('u.uid')->join('user_stat us', 'u.uid=us.uid','left')->where('u.uid', 1)->find();
	 *
	 * @return object $this 用于链式操作
	 */
	public function set_table_alias($alias='')
	{
		$alias = trim($alias);
		if ( ! in_array($alias, $this->db->qb_aliased_tables, TRUE))
		{
			$aliased_tables = $this->db->qb_aliased_tables;
			$aliased_tables[static::$table_name] = $alias;
			$this->db->qb_aliased_tables = $aliased_tables;
				
			if ($this->db->qb_caching === TRUE && ! in_array($alias, $this->db->qb_cache_aliased_tables, TRUE))
			{
				$qb_cache_exists = $this->db->qb_cache_exists;
				$qb_cache_aliased_tables = $this->db->qb_cache_aliased_tables;
				$qb_cache_aliased_tables[static::$table_name] = $alias;
				$qb_cache_exists[] = 'aliased_tables';

				$this->db->qb_cache_aliased_tables = $qb_cache_aliased_tables;
				$this->db->qb_cache_exists = $qb_cache_exists;
			}
		}
		return $this;
	}//end set_table_alias()

	//--------------------------------------------------------------------

	/**
	 * 获取主键名称
	 *
	 * @return string $this->key (当前model设置的表主键)
	 */
	public function get_key()
	{
		return $this->key;

	}//end get_key()

	//--------------------------------------------------------------------

	/**
	 * 将错误日志记录到文件中.
	 *
	 * 也可以扩展或者重写这个方法,将错误记录发送到控制台,方便进行进一步的处理.
	 *
	 * @param string $message 要写入的记录.
	 * @param string $level   日志级别,按CI log_message方法.
	 *
	 * @access protected
	 *
	 * @return mixed
	 */
	protected function logit($message, $level='debug')
	{
		if (empty($message))
		{
			return FALSE;
		}

		log_message($level, $message);

	}//end logit()

	//--------------------------------------------------------------------

	//--------------------------------------------------------------------
	// Further encapsulation of database processing
	//--------------------------------------------------------------------
	// Providing more database operation methods for CI in model
	//
	// It can be called this:
	//      $result = $this->model->select('...')
	//                            ->where('...')
	//                            ->having('...')
	//                            ->find();
	//

	public function select ($select = '*', $escape = NULL) { $this->db->select($select, $escape); return $this; }
	public function select_max ($select = '', $alias = '') { $this->db->select_max($select, $alias); return $this; }
	public function select_min ($select = '', $alias = '') { $this->db->select_min($select, $alias); return $this; }
	public function select_avg ($select = '', $alias = '') { $this->db->select_avg($select, $alias); return $this; }
	public function select_sum ($select = '', $alias = '') { $this->db->select_sum($select, $alias); return $this; }
	public function distinct ($val=TRUE) { $this->db->distinct($val); return $this; }
	public function from ($from) { $this->db->from($from); return $this; }
	public function join($table, $cond, $type = '') { $this->db->join($table, $cond, $type); return $this; }
	public function where($key, $value = NULL, $escape = TRUE) { $this->db->where($key, $value, $escape); return $this; }
	public function or_where($key, $value = NULL, $escape = TRUE) { $this->db->or_where($key, $value, $escape); return $this; }
	public function where_in($key = NULL, $values = NULL) { $this->db->where_in($key, $values); return $this; }
	public function or_where_in($key = NULL, $values = NULL) { $this->db->or_where_in($key, $values); return $this; }
	public function where_not_in($key = NULL, $values = NULL) { $this->db->where_not_in($key, $values); return $this; }
	public function or_where_not_in($key = NULL, $values = NULL) { $this->db->or_where_not_in($key, $values); return $this; }
	public function like($field, $match = '', $side = 'both') { $this->db->like($field, $match, $side); return $this; }
	public function not_like($field, $match = '', $side = 'both') { $this->db->not_like($field, $match, $side); return $this; }
	public function or_like($field, $match = '', $side = 'both') { $this->db->or_like($field, $match, $side); return $this; }
	public function or_not_like($field, $match = '', $side = 'both') { $this->db->or_not_like($field, $match, $side); return $this; }
	public function group_by($by) { $this->db->group_by($by); return $this; }
	public function having($key, $value = '', $escape = TRUE) { $this->db->having($key, $value, $escape); return $this; }
	public function or_having($key, $value = '', $escape = TRUE) { $this->db->or_having($key, $value, $escape); return $this; }
	public function limit($value, $offset = '') { $this->db->limit($value, $offset); return $this; }
	public function offset($offset) { $this->db->offset($offset); return $this; }
	public function set($key, $value = '', $escape = TRUE) { $this->db->set($key, $value, $escape); return $this; }
	public function trans_begin() { $this->db->trans_begin();}
	public function trans_commit() { $this->db->trans_commit();}
	public function trans_rollback() { $this->db->trans_rollback();}
	public function trans_status() { return $this->db->trans_status();}
	public function last_query() { return $this->db->last_query();}
	public function affected_rows() { return $this->db->affected_rows();}
	public function escape($str) { return $this->db->escape($str);}

	/**
	 * 开启缓存，缓存查询条件等等
	 * @param array $store_arr 需要缓存的部分，默认array('qb_join', 'qb_where', 'qb_groupby', 'qb_having', 'qb_aliased_tables', 'qb_no_escape')
	 * @return void
	 */
	public function start_store($store_arr = array('qb_join', 'qb_where', 'qb_groupby', 'qb_having', 'qb_aliased_tables', 'qb_no_escape'))
	{
		$store_arr = is_array($store_arr) ? $store_arr : array();
		foreach ($store_arr as $k=>$value) {
			// 此处为了兼容旧版含有ar_开始的CI版本
			$store_arr[$k] = preg_replace('/^ar_/', 'qb_', $value);
		}
		$this->db->qb_store_array = $store_arr;
	}

	/**
	 * 结束缓存
	 * @return void
	 */
	public function end_store()
	{
		$this->db->qb_store_array = array();
		$this->db->reset_select();
	}

}//end Test_Model

/* End of file Test_Model.php */